using System;
using System.Collections.Generic;
using System.Data;
using System.IO;
using System.Text.RegularExpressions;
using Google.Protobuf;
using Google.Protobuf.Reflection;
using HuaXianQu.ProtoBuffEx.Runtime;
using UnityEngine;

namespace HuaXianQu.ProtoBuffEx.ToolEditor
{
    public class SingleClassGen : IProtoToClassParse
    {
        /// <summary>
        /// excel功能总行数
        /// </summary>
        public const int FunctionRows = 5;

        /// <summary>
        /// proto变量编号所在行
        /// </summary>
        public const int protoCodeIndex = 1;

        /// <summary>
        /// proto变量类型所在行
        /// </summary>
        public const int protoTypeRow = 3;

        /// <summary>
        /// proto变量名称所在行
        /// </summary>
        public const int protoVarableNameRow = 4;

        private DataTable dataTable { get; set; }
        private Dictionary<string, VariableInfo> variableInfoDict;
        private List<VariableInfo> variableInfos;
        public string ClassName { get; set; }

        private IMessage excelDataMessage;
        private string DataaExe = "protodat";
        private string dataPath => ProtoPathConfig.Inst.GenerateProtoDataPath;
        private List<VariableInfo> variableInfoList;
        public const string ClassFeildName = "_singleclass";

        public void Parse(DataTable table)
        {
            dataTable = table;
            ClassName = table.TableName;
            ClassName = Regex.Replace(ClassName, $"{ClassFeildName}$", "", RegexOptions.IgnoreCase);
            CurObjectInfo.CustomVariableNameList.Add(ClassName);
            variableInfoList = new List<VariableInfo>();
            variableInfoDict = new();
            if (table.Columns.Count < FunctionRows)
            {
                return;
            }

            for (int i = 0; i < table.Rows.Count; i++)
            {
                DataRow data = table.Rows[i];
                string value = data[protoCodeIndex].ToString();
                if (!int.TryParse(value, out int index))
                {
                    continue;
                }

                value = data[protoVarableNameRow].ToString();
                if (string.IsNullOrEmpty(value))
                {
                    continue;
                }

                string type = data[protoTypeRow].ToString();
                if (string.IsNullOrEmpty(type))
                {
                    continue;
                }

                VariableInfo info = new VariableInfo()
                {
                    VariableName = value,
                    OriginVariableType = type,
                    ProtoIndex = index,
                    DataIndex = i,
                    ColumnCount = table.Columns.Count,
                    ExcelData = data,
                    DataRowCount = table.Rows.Count,
                };
                info.Parse();
                if (info.IsExistsCustomClass())
                {
                    CurObjectInfo.ReferenceOfVariableNameList.Add(info.CustomVariableName);
                }
                
                variableInfoList.Add(info);
                variableInfoDict.Add(info.VariableName, info);
            }
        }


        public void SetData()
        {
            if (ProtoBuffAssembleEditor.GetProtoBuffStatic(ClassName, out excelDataMessage, out Type messageType))
            {
                List<ExcelData> valueList = new();
                foreach (var field in excelDataMessage.Descriptor.Fields.InFieldNumberOrder())
                {
                    if (variableInfoDict.TryGetValue(field.Name, out VariableInfo info))
                    {
                        if (info.ColumnCount < FunctionRows + 1)
                        {
                            continue;
                        }

                        ExcelData excelData = ExcelData.GetExcelData(this);
                        excelData.CurVariableInfo = info;
                        string value = info.ExcelData[FunctionRows].ToString();
                        // Match match = Regex.Match(value,
                        //     @"[\s\t\n]*(?:(?:class)|(?:list)|:){1}[\s\t\n]*:[\s\t\n]*(\{[\w\W]*\})",
                        //     RegexOptions.IgnoreCase);

                        if (info.IsReadFirst) //如果通过class:标识定义整个类，直接区第一个值然后进入下一个变量
                        {
                            excelData.Data = value;
                            valueList.Add(excelData);
                            continue;
                        }

                        if (field.FieldType == FieldType.Message
                            || field.IsMap
                            || field.IsRepeated
                           )
                        {
                            for (int i = FunctionRows; i < info.ColumnCount; i++)
                            {
                                value = info.ExcelData[i].ToString();
                                if (!string.IsNullOrEmpty(value))
                                {
                                    if (field.IsMap || field.IsRepeated)
                                    {
                                        excelData.SetChild(value, i);
                                    }
                                    else
                                    {
                                        excelData.SetClassChild(value, i);
                                    }
                                }
                            }
                        }
                        else
                        {
                            excelData.Data = info.ExcelData[FunctionRows].ToString();
                        }

                        valueList.Add(excelData);
                    }
                    else
                    {
                        ProtoDebug.LogError($"{ClassName}.{field.Name}===数据异常");
                    }
                }

                ClassGen classTemp = new ClassGen();
                classTemp.SetProtoBuffDataToClass(ref excelDataMessage, null, valueList);
            }
        }

        public bool SaveData()
        {
            if (!Directory.Exists(dataPath))
            {
                Directory.CreateDirectory(dataPath);
            }

            try
            {
                using (FileStream writer = File.Create($"{dataPath}/{ClassName}.{DataaExe}"))
                {
                    using (CodedOutputStream codedOutputStream = new CodedOutputStream(writer))
                    {
                        excelDataMessage.WriteTo(codedOutputStream);
                        return true;
                    }
                }
            }
            catch (Exception e)
            {
                ProtoDebug.LogError($"{ClassName}数据写入错误，err:{e}");
            }

            return false;
        }


        public ObjectInfo CurObjectInfo { get; set; } = new ObjectInfo();
        public bool IsDataClass { get; set; }

        public override string ToString()
        {
            return $"message {ClassName}\n{{ \n{string.Join('\n', variableInfoList)}\n}}";
        }
    }
}